package com.apikey.auth.repository;

import com.apikey.auth.entity.Application;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * API Key申请记录Repository接口
 * 提供申请记录的数据访问操作
 *
 * @author API Key Framework
 * @version 1.0
 */
@Repository
public interface ApplicationRepository extends JpaRepository<Application, Long> {

    /**
     * 根据手机号查找申请记录
     *
     * @param phoneNumber 手机号
     * @return 申请记录列表
     */
    List<Application> findByPhoneNumber(String phoneNumber);

    /**
     * 根据手机号查找申请记录，按申请时间倒序排列
     *
     * @param phoneNumber 手机号
     * @return 申请记录列表
     */
    List<Application> findByPhoneNumberOrderByApplyTimeDesc(String phoneNumber);

    /**
     * 根据手机号和验证密码查找申请记录
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码
     * @return 申请记录
     */
    Optional<Application> findByPhoneNumberAndVerifyPassword(String phoneNumber, String verifyPassword);

    /**
     * 根据手机号和验证密码查找申请记录，按申请时间倒序排列
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码
     * @return 申请记录列表
     */
    List<Application> findByPhoneNumberAndVerifyPasswordOrderByApplyTimeDesc(String phoneNumber, String verifyPassword);

    /**
     * 根据手机号和浏览器指纹查找申请记录
     *
     * @param phoneNumber 手机号
     * @param fingerprint 浏览器指纹
     * @return 申请记录
     */
    Optional<Application> findByPhoneNumberAndFingerprint(String phoneNumber, String fingerprint);

    /**
     * 根据浏览器指纹查找申请记录
     *
     * @param fingerprint 浏览器指纹
     * @return 申请记录列表
     */
    List<Application> findByFingerprint(String fingerprint);

    /**
     * 根据浏览器指纹查找申请记录，按申请时间倒序排列
     *
     * @param fingerprint 浏览器指纹
     * @return 申请记录列表
     */
    List<Application> findByFingerprintOrderByApplyTimeDesc(String fingerprint);

    /**
     * 根据状态查找申请记录
     *
     * @param status 申请状态
     * @return 申请记录列表
     */
    List<Application> findByStatus(Application.Status status);

    /**
     * 根据状态分页查找申请记录
     *
     * @param status   申请状态
     * @param pageable 分页参数
     * @return 申请记录分页结果
     */
    Page<Application> findByStatus(Application.Status status, Pageable pageable);

    /**
     * 根据审核人查找申请记录
     *
     * @param reviewer 审核人
     * @return 申请记录列表
     */
    List<Application> findByReviewer(String reviewer);

    /**
     * 根据审核人分页查找申请记录
     *
     * @param reviewer 审核人
     * @param pageable 分页参数
     * @return 申请记录分页结果
     */
    Page<Application> findByReviewer(String reviewer, Pageable pageable);

    /**
     * 查找指定时间范围内的申请记录
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 申请记录列表
     */
    List<Application> findByApplyTimeBetween(LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 查找指定时间范围内的申请记录（分页）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 申请记录分页结果
     */
    Page<Application> findByApplyTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);

    /**
     * 统计各状态的申请数量
     *
     * @return 状态统计结果
     */
    @Query("SELECT a.status, COUNT(a) FROM Application a GROUP BY a.status")
    List<Object[]> countByStatus();

    /**
     * 统计指定状态的申请数量
     *
     * @param status 申请状态
     * @return 申请数量
     */
    long countByStatus(String status);

    /**
     * 统计今日申请数量
     *
     * @param startOfDay 今日开始时间
     * @return 今日申请数量
     */
    @Query("SELECT COUNT(a) FROM Application a WHERE a.applyTime >= :startOfDay")
    long countTodayApplications(@Param("startOfDay") LocalDateTime startOfDay);

    /**
     * 统计本月申请数量
     *
     * @param startOfMonth 本月开始时间
     * @return 本月申请数量
     */
    @Query("SELECT COUNT(a) FROM Application a WHERE a.applyTime >= :startOfMonth")
    long countThisMonthApplications(@Param("startOfMonth") LocalDateTime startOfMonth);

    /**
     * 查找待审核的申请记录
     *
     * @param pageable 分页参数
     * @return 待审核申请记录分页结果
     */
    Page<Application> findByStatusOrderByApplyTimeAsc(Application.Status status, Pageable pageable);

    /**
     * 查找最近的申请记录
     *
     * @param limit 限制数量
     * @return 最近申请记录列表
     */
    @Query("SELECT a FROM Application a ORDER BY a.applyTime DESC")
    List<Application> findRecentApplications(Pageable pageable);

    /**
     * 检查指定手机号是否存在指定状态的申请记录
     *
     * @param phoneNumber 手机号
     * @param statuses    状态列表
     * @return 是否存在
     */
    boolean existsByPhoneNumberAndStatusIn(String phoneNumber, List<String> statuses);

    /**
     * 检查指定浏览器指纹是否存在指定状态的申请记录
     *
     * @param fingerprint 浏览器指纹
     * @param statuses    状态列表
     * @return 是否存在
     */
    boolean existsByFingerprintAndStatusIn(String fingerprint, List<String> statuses);

    /**
     * 查找指定手机号的最新申请记录
     *
     * @param phoneNumber 手机号
     * @return 最新申请记录
     */
    @Query("SELECT a FROM Application a WHERE a.phoneNumber = :phoneNumber ORDER BY a.applyTime DESC")
    Optional<Application> findLatestByPhoneNumber(@Param("phoneNumber") String phoneNumber);

    /**
     * 查找指定浏览器指纹的最新申请记录
     *
     * @param fingerprint 浏览器指纹
     * @return 最新申请记录
     */
    @Query("SELECT a FROM Application a WHERE a.fingerprint = :fingerprint ORDER BY a.applyTime DESC")
    Optional<Application> findLatestByFingerprint(@Param("fingerprint") String fingerprint);

    /**
     * 统计指定时间范围内各状态的申请数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 状态统计结果
     */
    @Query("SELECT a.status, COUNT(a) FROM Application a WHERE a.applyTime BETWEEN :startTime AND :endTime GROUP BY a.status")
    List<Object[]> countByStatusAndTimeBetween(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 查找超时未审核的申请记录
     *
     * @param timeoutTime 超时时间点
     * @return 超时申请记录列表
     */
    @Query("SELECT a FROM Application a WHERE a.status = 'PENDING' AND a.applyTime < :timeoutTime")
    List<Application> findTimeoutApplications(@Param("timeoutTime") LocalDateTime timeoutTime);

    /**
     * 统计指定浏览器指纹的申请总数（所有状态）
     *
     * @param fingerprint 浏览器指纹
     * @return 申请总数
     */
    long countByFingerprint(String fingerprint);
}